package com.xinting.piano.service;

import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;

import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.xinting.piano.app.PRoutineService;
import com.xinting.piano.data.PApp;
import com.xinting.piano.data.PError;
import com.xinting.piano.data.PUser;
import com.xinting.piano.lib.network.PNetWork;
import com.xinting.piano.lib.storage.PSharePreferences;
import com.xinting.piano.lib.util.PUtil;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by wuxinting on 15/11/5.
 * 账号相关的操作,业务
 */
public class PAccount {

    private static PAccount account;
    private Status status = Status.LOGOUT;
    //当前登录用户
    private PUser user;
    //当前的token
    private String currentToken;
    //routine service
    private Messenger service;

    //public static define
    public static final String LOG_TAG = PApp.LOG_TAG+"_account";
    public static final String KEY_TOKEN = "token";
    public static final String KEY_USERNAME = "username";
    public static final String KEY_NICK = "nickname";
    public static final String KEY_PASSWORD = "passwd";
    public static final String KEY_VERIFY_CODE = "verify";

    public static final String URL_APPLY = "account/apply";
    public static final String URL_LOGIN = "account/login";
    public static final String URL_VERIFY = "account/verify";
    public static final String URL_CHECK_USER = "account/check_user";

    public enum Status {
        LOGOUT, //登出状态
        TO_VERIFY, //发出发送验证码的请求
        VERIFY, //服务器已经发送验证码
        TO_APPLY, //发出注册请求
        APPLY, //注册成功, 服务器会自动登录，注册成功也会返回token
        TO_LOGIN, //发送登录请求
        LOGIN, //已经登录，返回token
    }

    public static PAccount getInstance() {
        synchronized (PAccount.class) {
            if (account == null) {
                synchronized (PAccount.class) {
                    account = new PAccount();
                }
            }
        }
        return account;
    }

    /**
     * 获取当前账号的状态
     * @return
     */
    public Status getStatus() {
        return status;
    }

    /**
     * 设置账号状态，只可以在业务内部改变
     * @param status
     */
    private void setStatus(Status status) {
        this.status = status;
        PBroadcast.getInstance().broadcast(PApp.BC_ACCOUNT_STATUS_CHANGE, status);
    }

    /**
     * 返回当前登录用户
     * @return
     */
    public PUser getCurrentUser() {
        return user;
    }

    /**
     * 设置当前登录的用户，只可以业务内部改变状态
     * @param user
     */
    private void setCurrentUser(PUser user) {
        this.user = user;
    }

    /**
     * 检查一个用户是否存在
     * @param user 包含phone即可
     * @return
     */
    public boolean checkUser(PUser user, IHandleJson handleJson) {
        String url = PUtil.joinURL(PApp.URL_SERVER, URL_CHECK_USER);
        Map<String, String> params = new HashMap<>();
        params.put(KEY_USERNAME, user.getPhone());
        try {
            PNetWork.getInstance().post(url, params, new HandleJson(handleJson));
        } catch (IOException e) {
            Log.e(LOG_TAG, e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * send verify code to phone.
     * @param phone
     */
    public void sendVerifyCode(String phone, final IHandleJson handleJson) {
        String url = PUtil.joinURL(PApp.URL_SERVER, URL_VERIFY);
        url += "?phone=" + phone;

        try {
            PNetWork.getInstance().get(url, new HandleJson(handleJson));
        } catch (IOException e) {
            Log.e(PApp.LOG_TAG, e.getMessage());
        }

        Log.v(PApp.LOG_TAG, "verify " + url);
        //表示已经发送了验证码
        setStatus(Status.TO_VERIFY);
    }

    /**
     * apply user
     * @param user contain user's name (phone number)
     * @param passwd user's password
     * @param verify the verify code
     * @return true false
     */
    public boolean apply(PUser user, String passwd, String verify, final IHandleJson handleJson) {
        Map<String, String> params = new HashMap<>();
        params.put(KEY_USERNAME, user.getPhone());
        params.put(KEY_PASSWORD, passwd);
        params.put(KEY_VERIFY_CODE, verify);

        try {
            String nick = URLEncoder.encode(user.getNick(), "UTF-8");
            params.put(KEY_NICK, nick);
            params.put(KEY_NICK, user.getNick());
        } catch (UnsupportedEncodingException e) {
            Log.e(LOG_TAG, "Account encode nick "+e.toString());
            return false;
        }

        try {
            PNetWork.getInstance().post(PUtil.joinURL(PApp.URL_SERVER, URL_APPLY), params, new HandleJson(handleJson));
        } catch (IOException e) {
            Log.e(PApp.LOG_TAG, e.getMessage());
            return false;
        }

        setStatus(Status.TO_APPLY);
        return true;
    }

    /**
     * login user
     * @param user
     * @return
     */
    public boolean login(PUser user, String passwd, String verify, final IHandleJson handleJson) {
        Map<String, String> params = new HashMap<>();
        params.put(KEY_USERNAME, user.getPhone());
        params.put(KEY_PASSWORD, passwd);

        if (!TextUtils.isEmpty(verify)) {
            params.put(KEY_VERIFY_CODE, verify);
        }

        try {
            PNetWork.getInstance().post(PUtil.joinURL(PApp.URL_SERVER, URL_LOGIN), params, new HandleJson(handleJson));
        } catch (Exception e) {
            Log.e(PApp.LOG_TAG, e.getMessage());
            return false;
        }

        setStatus(Status.TO_LOGIN);
        return true;
    }

    /**
     * 用token登录
     * @return
     */
    public boolean loginByToken() {
        Log.v(LOG_TAG, "login by token start");
        Map<String, String> params = new HashMap<>();

        String token = new PSharePreferences(PApp.getAppContext()).get(KEY_TOKEN);
        if (token == null || token.isEmpty()) {
            PBroadcast.getInstance().broadcast(PApp.BC_ACCOUNT_INVALID_TOKEN, null);
            Log.w(PApp.LOG_TAG, "no token");
            return false;
        }

        params.put(KEY_TOKEN, token);
        Log.v(LOG_TAG, "token " + token);

        try {
            PNetWork.getInstance().post(PUtil.joinURL(PApp.URL_SERVER, URL_LOGIN), params, new HandleJson(null));
        } catch (IOException e) {
            Log.e(PApp.LOG_TAG, e.getMessage());
            return false;
        }

        setStatus(Status.TO_LOGIN);
        return true;
    }

    /**
     * 对外提供的相关token的接口
     * @param param
     */
    public void fillTokenToParam(Map<String, String> param) {
        String token = new PSharePreferences(PApp.getAppContext()).get(KEY_TOKEN);
        if (token != null) {
            param.put(KEY_TOKEN, token);
            Log.v(LOG_TAG, token);
        }
    }

    /**
     * 登录日常
     * @param messenger
     */
    public void addRoutine(Messenger messenger) {
        Message msg = Message.obtain(null, PRoutineService.MSG_ADD_ROUTINE_TASK);
        msg.obj = new RoutineAccountTask();
        try {
            messenger.send(msg);
        } catch (RemoteException e) {
            Log.e(LOG_TAG, e.getMessage());
        }
    }

    /**
     * 移除日常
     */
    public void removeRoutine() {
        if (service != null) {
            Message msg = Message.obtain(null, PRoutineService.MSG_RM_ROUTINE_TASK);
            msg.arg1 = PApp.ROUTINE_ACCOUNT;
            try {
                service.send(msg);
            } catch (RemoteException e) {
                Log.e(LOG_TAG, e.toString());
            }
        }
    }

    /**
     * 保存登录成功后返回的信息
     * @param json
     */
    private void saveLoginUser(JSONObject json) {
        try {
            if (json.has(PUser.KEY)) {
                PUser user = new PUser();
                user.fromJson(json.getJSONObject(PUser.KEY));
                setCurrentUser(user);
            }

            if (json.has(KEY_TOKEN)) {
                PSharePreferences sharePreferences = new PSharePreferences(PApp.getAppContext());
                sharePreferences.save(KEY_TOKEN, json.getString(KEY_TOKEN));
            }
        } catch (JSONException e) {
            Log.e(PApp.LOG_TAG, e.getMessage());
        }
    }

    /**
     * 统一处理网络库返回的信息
     */
    private class HandleJson implements PNetWork.IHandleHttpResult {

        private final IHandleJson handleJson;

        public HandleJson(IHandleJson handleJson) {
            this.handleJson = handleJson;
        }

        @Override
        public void onRequest(Request req, IOException e) {
            Log.e(PApp.LOG_TAG, "error"+e.toString());
            PBroadcast.getInstance().broadcast(PApp.BC_NETWORK_ERROR, null);

            if (handleJson != null) {
                handleJson.handleJson(null);
            }

            setStatus(Status.LOGOUT);
        }

        @Override
        public void onResponse(Response res) throws IOException {
            JSONObject json;
            int code;

            try {
                String resStr = res.body().string();
                Log.v(LOG_TAG, resStr);

                json = new JSONObject(resStr);
                code = json.optInt(PError.KEY_CODE, PError.ERR_UNKNOWN);

                if (code == PError.ERR_INVALID_TOKEN) {
                    PBroadcast.getInstance().broadcast(PApp.BC_ACCOUNT_INVALID_TOKEN, null);
                }

            } catch (Exception e) {
                Log.e(LOG_TAG, "Account response error " + e.toString());
                setStatus(Status.LOGOUT);
                return;
            }

            // 如果成功改变状态
            if (code == PError.ERR_SUCCESS) {
                switch (getStatus()) {
                    case TO_VERIFY:
                        setStatus(Status.VERIFY);
                        break;
                    case TO_APPLY:
                    case TO_LOGIN:
                        saveLoginUser(json);
                        //应该将状态转化放在后面，因为此时新的账号信息才保存成功
                        setStatus(Status.LOGIN);

                        //移除routine
                        removeRoutine();
                        break;
                    default:
                        break;
                }
            } else {
                setStatus(Status.LOGOUT);
            }

            if (handleJson != null) {
                handleJson.handleJson(json);
            }

        }
    }

    //日常登录
    private class RoutineAccountTask implements PRoutineService.IRoutineTask {

        @Override
        public int getId() {
            return PApp.ROUTINE_ACCOUNT;
        }

        @Override
        public long getDelay() {
            return 0;
        }

        @Override
        public long getPeriod() {
            //每1分钟登录一次，如果登录成功，则移除
            return 60*1000;
        }

        @Override
        public void setMessenger(Messenger messenger) {
            service = messenger;
        }

        @Override
        public void run() {
            loginByToken();
        }
    }
}
